package com.jiangyg.devtools.execute.beantojson;

import com.intellij.psi.*;
import com.jiangyg.devtools.toolkit.JsonUtils;
import com.jiangyg.devtools.toolkit.random.ChineseNameCreator;
import org.apache.commons.lang.RandomStringUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;

import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 类描述：根据 PsiFile 转换成 JSON 对象
 *
 * @author jiangyg
 * @date 2023-08-15
 */
public class PsiFileJsonCreator {

    private final PsiFile file;

    private final Map<String, Object> oo = new HashMap<>();

    public PsiFileJsonCreator(PsiFile file) {
        this.file = file;
    }

    /**
     * 功能描述：生成JSON字符串
     *
     * @return JSON字符串
     */
    public String create() {
        final PsiElement[] elements = file.getChildren();
        for (PsiElement element : elements) {
            if (!(element instanceof PsiClass)) {
                continue;
            }
            this.handlePsiClassElement((PsiClass) element);
        }
        return JsonUtils.toJSONString(oo);
    }

    /**
     * 功能描述：处理每个 PsiClass 元素
     *
     * @param element 元素
     */
    private void handlePsiClassElement(PsiClass element) {
        final PsiField[] fields = element.getAllFields();
        for (final PsiField field : fields) {
            // 序列化字段忽略
            if (StringUtils.equals(field.getName(), "serialVersionUID")) {
                continue;
            }
            // 字段随机值
            final PsiType type = field.getType();
            final Object value = createBeanPropRandomValue(type.getCanonicalText(), field);
            if (value == null) {
                continue;
            }
            oo.put(field.getName(), value);
        }
    }

    /**
     * 功能描述：生成 Bean 属性的随机值
     *
     * @param canonicalText 类型名称
     * @param field         字段信息
     * @return 随机值
     */
    private Object createBeanPropRandomValue(String canonicalText, PsiField field) {
        // 数组类型
        if (StringUtils.endsWith(canonicalText, "[]")) {
            final String canonicalTextTmp = canonicalText.substring(0, canonicalText.length() - 2);

            final int len = ThreadLocalRandom.current().nextInt(1, 10);
            final Object[] arrs = new Object[len];
            for (int i = 0; i < len; i++) {
                arrs[i] = createBeanPropRandomValue(canonicalTextTmp, field);
            }

            return arrs;
        }

        // 非数组类型处理
        return createNotArrayTypeOfBeanPropRandomValue(canonicalText, field);
    }

    /**
     * 功能描述：生成非数组类型 Bean 属性的随机值
     *
     * @param canonicalText 类型名称
     * @param field         字段信息
     * @return 随机值
     */
    private Object createNotArrayTypeOfBeanPropRandomValue(String canonicalText, PsiField field) {
        // 处理泛型的
        final Matcher matcher = Pattern.compile("(?<type1>[^<>]+)<(?<type2>.+)>").matcher(canonicalText);
        if (matcher.find()) {
            try {
                final String type1 = matcher.group("type1");
                final Class<?> clazz = this.getClass().getClassLoader().loadClass(type1);

                // java.util.List<java.lang.String>
                if (java.util.Collection.class.isAssignableFrom(clazz)) {
                    final int size = ThreadLocalRandom.current().nextInt(1, 10);
                    final List<Object> dataList = new ArrayList<>();
                    for (int i = 0; i < size; i++) {
                        final String type2 = matcher.group("type2");
                        dataList.add(createBeanPropRandomValue(type2, field));
                    }
                    return dataList;
                }

                // java.util.Map<.., ..>
                if (java.util.Map.class.isAssignableFrom(clazz)) {
                    return Collections.emptyMap();
                }

                // TODO more
            } catch (Exception ex) {
                // ignore
                // ex.printStackTrace();
            }
        }

        // 基本类型的随机值
        return createBaseTypeOfBeanPropRandomValue(canonicalText);
    }

    /**
     * 功能描述：根据类型名称生成随机值
     *
     * @param canonicalText 类型名称
     * @return 随机值
     */
    private Object createBaseTypeOfBeanPropRandomValue(String canonicalText) {
        if (StringUtils.equals(String.class.getName(), canonicalText)) {
            // return RandomStringUtils.random(6);
            return new ChineseNameCreator().create();
        }

        if (StringUtils.equals("short", canonicalText)
                || StringUtils.equals("int", canonicalText)
                || StringUtils.equals("long", canonicalText)
                || StringUtils.equals(Short.class.getName(), canonicalText)
                || StringUtils.equals(Integer.class.getName(), canonicalText)
                || StringUtils.equals(Long.class.getName(), canonicalText)) {
            return ThreadLocalRandom.current().nextInt(0, 100);
        }

        if (StringUtils.equals("double", canonicalText)
                || StringUtils.equals("float", canonicalText)
                || StringUtils.equals(Double.class.getName(), canonicalText)
                || StringUtils.equals(Float.class.getName(), canonicalText)) {
            return ThreadLocalRandom.current().nextDouble(0, 100);
        }

        if (StringUtils.equals("char", canonicalText)
                || StringUtils.equals(Character.class.getName(), canonicalText)) {
            return RandomStringUtils.randomAlphabetic(1).charAt(0);
        }

        if (StringUtils.equals("boolean", canonicalText)
                || StringUtils.equals(Boolean.class.getName(), canonicalText)) {
            return ThreadLocalRandom.current().nextBoolean();
        }

        if (StringUtils.equals(Date.class.getName(), canonicalText)) {
            final int day = ThreadLocalRandom.current().nextInt(0, 31);
            Date date = DateUtils.addDays(new Date(), -day);
            final int month = ThreadLocalRandom.current().nextInt(0, 12);
            date = DateUtils.addMonths(date, -month);
            final int year = ThreadLocalRandom.current().nextInt(0, 10);
            date = DateUtils.addYears(date, -year);
            return DateFormatUtils.format(date, "yyyy-MM-dd hh:mm:ss");
        }

        // TODO more
        return null;
    }

}
